#include <dirent.h>
#include <stdio.h>
#include <errno.h>
#include <stdbool.h>

//struct dirent
//{
//   long d_ino; /* inode number 索引节点号 */
//   off_t d_off; /* offset to this dirent 在目录文件中的偏移 */
//   unsigned short d_reclen; /* length of this d_name 文件名长 */
//   unsigned char d_type; /* the type of d_name 文件类型 */
//   char d_name [NAME_MAX+1]; /* file name (null-terminated) 文件名，最长255字符 */
//}
//

#define MAX_READ_NUM 2

/* 
* 返回值
*     true: 读到 maxReadNum 或者目录结尾返回 true, 读到目录结尾时 outReadNum < maxReadNum
*			如果最后一次读取了 maxReadNum 后到达目录结尾，会多读一次，读取 0 个目录条目
*     false: 发生错误返回 false
*
*/
bool readdirOffset(off_t offset, int maxReadNum, off_t* outOff, int *outReadNum)
{
	DIR *dir;
	struct dirent *entry;
	*outReadNum = 0;

	// 打开目录
	dir = opendir(".");

	// 偏移
	seekdir(dir, offset);

	// readdir 执行成功时返回子目录(文件)指针，若读取到目录文件尾则返回NULL
    // 执行失败也会返回 NULL
    // 因此要根据返回值和 errno 共同判断函数执行成功还是失败
	while ((entry = readdir(dir)) != NULL) {
		*outOff = entry->d_off;
		// 获取文件或目录的名称
		printf("\tname:%s, nameLen:%d, offset:%ld\n",
				entry->d_name, entry->d_reclen, entry->d_off);

		(*outReadNum)++;
		if (*outReadNum >= maxReadNum)
			break;
	}

	printf("\t---return: readNum=%d offset=%ld errno=%d\n",*outReadNum, *outOff, errno);

	if ((entry == NULL) && errno)
		return false; // error

	// 关闭目录
	closedir(dir);
	return true;
}

int main() 
{
	int i = 0;
	int maxReadNum = 3;
	int outReadNum = 0;
	off_t seekOff = 0;
	off_t outNewOff = 0;

	while (readdirOffset(seekOff, maxReadNum, &outNewOff, &outReadNum))
	{
		printf("====%d===curSeekoff:%ld, outNewOff=%ld curReadNum=%d\n", i++, seekOff, outNewOff, outReadNum);
		if (outReadNum < maxReadNum)
			break;
		seekOff = outNewOff;
	}

	return 0;
}
